603E - Pastoral Oddities - CodeForces Solution


data structures divide and conquer dsu math trees *3000

Please click on ads to support us..

C++ Code:

#include <sstream>
#include <fstream>
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>
#include <set>
#include <map>
#include <string>
#include <cstring>
#include <stack>
#include <queue>
#include <cmath>
#include <ctime>
#include <utility>
#include <cassert>
#include <bitset>
#include <functional>
#include <random>
using namespace std;
#define REP(I,N) for (I=0;I<N;I++)
#define rREP(I,N) for (I=N-1;I>=0;I--)
#define rep(I,S,N) for (I=S;I<N;I++)
#define rrep(I,S,N) for (I=N-1;I>=S;I--)
#define FOR(I,S,N) for (I=S;I<=N;I++)
#define rFOR(I,S,N) for (I=N;I>=S;I--)

#define DEBUG
#ifdef DEBUG
#define debug(...) fprintf(stderr, __VA_ARGS__)
#define deputs(str) fprintf(stderr, "%s\n",str)
#else
#define debug(...)
#define deputs(str)
#endif // DEBUG
typedef unsigned long long ULL;
typedef unsigned long long ull;
typedef unsigned int ui;
typedef long long LL;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
const int INF=0x3f3f3f3f;
const LL INFF=0x3f3f3f3f3f3f3f3fll;
const LL M=1e9+7;
// const LL M=998244353;
// ll M=1;
const LL maxn=1e6+107;
const double pi=acos(-1.0);
const double eps=0.0000000001;
template<typename T>inline T gcd(T a, T b) {return b?gcd(b,a%b):a;}
template<typename T>inline void pr2(T x,int k=64) {ll i; REP(i,k) debug("%d",(x>>i)&1); putchar(' ');}
template<typename T>inline void add_(T &A,int B,ll MOD=M) {A+=B; (A>=MOD) &&(A-=MOD);}
template<typename T>inline void mul_(T &A,ll B,ll MOD=M) {A=(A*B)%MOD;}
template<typename T>inline void mod_(T &A,ll MOD=M) {A%=MOD; A+=MOD; A%=MOD;}
template<typename T>inline void max_(T &A,T B) {(A<B) &&(A=B);}
template<typename T>inline void min_(T &A,T B) {(A>B) &&(A=B);}
template<typename T>inline T abs(T a) {return a>0?a:-a;}
template<typename T>inline T fastgcd(T a, T b) {
    int az=__builtin_ctz(a),bz=__builtin_ctz(b),z=min(az,bz),diff; b>>=bz;
    while (a) {
        a>>=az; diff=b-a; az=__builtin_ctz(diff);
        min_(b,a); a=abs(diff);
    }
    return b<<z;
}
inline ll powMM(ll a, ll b, ll mod=M) {
    ll ret=1;
    for (; b; b>>=1ll,a=a*a%mod)
        if (b&1) ret=ret*a%mod;
    return ret;
}
int startTime;
void startTimer() {startTime=clock();}
void printTimer() {debug("/--- Time: %ld milliseconds ---/\n",clock()-startTime);}
typedef array<int,4> ar4;
typedef array<int,3> ar3;
std::mt19937 rng(time(0));
std::mt19937_64 rng64(time(0));

template<bool path_compression=true>
struct DSU {
    vector<int> checkpoint_;
    vector<pii> changes_;
    vector<int> fa; // fa[x]<0: root; and we save its size
    DSU(int n) {fa.resize(n+1,-1);} // fa<0: size; else: real-getfather
    inline int getfa(int x) {
        if (path_compression) {
            if (fa[x]<0) return x;
            int ret=getfa(fa[x]);
            if (ret!=fa[x]) changes_.push_back({x,fa[x]});
            return fa[x]=ret;
        } else {
            while (fa[x]>=0) x=fa[x];
            return x;
        }
    }
    void checkpoint() {
        checkpoint_.push_back(changes_.size());
    }
    inline void undo() { // single undo
        pii p=changes_.back();
        fa[p.first]=p.second;
        changes_.pop_back();
    }
    void rollback() { // rollback to checkpoint (stack)
        while ((int)changes_.size()!=checkpoint_.back()) undo();
        checkpoint_.pop_back();
    }
    void merge(int x,int y) {
        x=getfa(x); y=getfa(y);
        if (x==y) return;
        if (-fa[x]>-fa[y]) swap(x,y);
        changes_.push_back({x,fa[x]});
        changes_.push_back({y,fa[y]});
        fa[y]+=fa[x]; fa[x]=y; // sz and fa
    }
    void merge_solve(int x,int y) {
        x=getfa(x); y=getfa(y);
        if (x==y) return;
        int newodds=fa.back();
        newodds-=fa[x]&1;
        newodds-=fa[y]&1;
        if (-fa[x]>-fa[y]) swap(x,y);
        changes_.push_back({x,fa[x]});
        changes_.push_back({y,fa[y]});
        fa[y]+=fa[x]; fa[x]=y; // sz and fa
        newodds+=fa[y]&1;
        if (newodds!=fa.back())
            changes_.push_back({fa.size()-1,fa.back()});
        fa.back()=newodds;

        // int i;
        // FOR(i,1,fa.size()-2) printf("%d ",fa[i]); printf("<- fa; odd=%d\n",fa.back());
    }
};
struct TheStack { // stack-like structure
    // DSU<false> dsu;
    DSU<false> dsu;
    int tot=0;
    TheStack(int n):dsu(n) { // rollback to checkpoint needs n+1!
        dsu.fa.push_back(n); // odd number
    }
    void push(int x,int y) {
        dsu.checkpoint();
        dsu.merge_solve(x,y);
    }
    void pop() {dsu.rollback();}
    bool good() {return dsu.fa.back()==0;}
};
struct ThePriorityQueue {
    vector<pair<ar3,int>> items; // item (input), position in the stack 
    TheStack the_stack; // a stack-like structure, which adopts rollback
    vector<int> updates; // id in the stack
    set<pii> where; // priority, id
    ThePriorityQueue(int n):the_stack(n) {}
    void push_into_stack(int id) {
        items[id].second=updates.size(); // position
        updates.push_back(id); // updates id
        the_stack.push(items[id].first[0],items[id].first[1]); // insert into the stack
    }
    int pop_from_stack() { // return id
        int topid=updates.back();
        updates.pop_back(); //redo
        the_stack.pop(); // O(1)
        return topid;
    }
    void insert(int id) { // insert into set
        where.insert({items[id].first[2],id}); // insert priority into set
        push_into_stack(id);
    }
    void push(int x,int y,int w) { // new item
        items.push_back({{x,y,w},updates.size()});
        insert(items.size()-1); // push the newly inserted item!
    }
    pair<ar3,int> pop() {
        int bestid=where.rbegin()->second; // lastval-id
        int need=items[bestid].second; // position of the last item in the stack
        if ((int)updates.size()==need) { // bestid == updates.back()
            pop_from_stack();
        } else { // relax
            auto it=where.end();
            vector<int> redo_large,redo_small;
            int k=1; pii split; // number of pops
            for (int q=0;q<(k+1)/2;q++) {
                it--; split=*it; int id=it->second; // >=split: large
                int need=items[id].second;
                if (q) redo_large.push_back(id);
                // else assert(bestid==split.second);
                // no +1?(todo), because we have already pop the max item
                k=max(k,(int)updates.size()-need);
                // printf("solve large %d %d: pos=%d\n",split.first,split.second,updates.size()-need);
            } // roll-back-insert
            reverse(redo_large.begin(),redo_large.end());
            // printf("\nsolve k=%d; split=%d %d\n",k,split.first,split.second);
            vector<int> redo_all;
            while (k--) {
                int id=pop_from_stack();
                // printf("redo pop from stack %d %d\n",items[id].first[2],id);
                if (make_pair(items[id].first[2],id)<split) redo_small.push_back(id);
                redo_all.push_back(id);
            }
            // for (int id:redo_all) printf("%d ",id); puts("<- redo all");
            // for (int id:redo_small) printf("%d ",id); puts("<- redo small");
            // for (int id:redo_large) printf("%d ",id); puts("<- redo large");

            assert(redo_all.size()==redo_small.size()+redo_large.size()+1);

            for (int id:redo_small) push_into_stack(id); // x,y,w
            for (int id:redo_large) push_into_stack(id); // x,y,w
        }

        int w=items[bestid].first[2]; where.erase({w,bestid});
        return {items[bestid].first,bestid}; // the popped item could be roll-back! (just push)
    }
    bool good() {
        return the_stack.good();
    }
};

int A[maxn];
int main() {
    int n,m;
    scanf("%d%d",&n,&m);
    ThePriorityQueue Q(n);
    while (m--) {
        int x,y,w;
        scanf("%d%d%d",&x,&y,&w);
        Q.push(x,y,w);
        if (!Q.good()) puts("-1");
        else {
            auto p=Q.pop();
            while (Q.good()) p=Q.pop(); // value, id
            Q.insert(p.second);
            printf("%d\n",p.first[2]);
        }
    }
}
/*
*/


Comments

Submit
0 Comments
More Questions

807A - Is it rated
1096A - Find Divisible
1430C - Numbers on Whiteboard
1697B - Promo
208D - Prizes Prizes more Prizes
659A - Round House
1492C - Maximum width
171B - Star
1512B - Almost Rectangle
831B - Keyboard Layouts
814A - An abandoned sentiment from past
268C - Beautiful Sets of Points
1391C - Cyclic Permutations
11A - Increasing Sequence
1406A - Subset Mex
1365F - Swaps Again
50B - Choosing Symbol Pairs
1719A - Chip Game
454B - Little Pony and Sort by Shift
1152A - Neko Finds Grapes
1719B - Mathematical Circus
1719C - Fighting Tournament
1642A - Hard Way
285C - Building Permutation
1719E - Fibonacci Strings
1696C - Fishingprince Plays With Array
1085A - Right-Left Cipher
1508B - Almost Sorted
1690C - Restoring the Duration of Tasks
1055A - Metro